import { isEqual } from 'lodash-es';
import { Application, Assets, AnimatedSprite, Spritesheet, Texture, Container, Graphics } from 'pixi.js';
import { Tween, Easing } from '@tweenjs/tween.js'
import { createApp } from 'vue';
import Topbar from './components/Topbar.vue';
import { gameStore } from './store/game';
import "@/assets/styles/tailwind.css"
// The application will create a renderer using WebGL, if possible,
// with a fallback to a canvas render. It will also setup the ticker
// and the root stage PIXI.Container
createApp(Topbar).mount('#app')
const app = new Application();
app.init({ background: '#000000', resizeTo: window }).then(async () => {
    document.body.appendChild(app.canvas);
    const stage = new Container();
    const gridSize = 60; // 格子大小
    const gridContainer = new Container();
    stage.x = 20
    stage.addChild(gridContainer);
    app.stage.addChild(stage);
    await Assets.load(["/assets/Unit_mov1.png"])

    for (let i = 0; i < 10; i++) {
        for (let j = 0; j < 10; j++) {
            const graphics = new Graphics();
            graphics.label = `${i}_${j}`
            gridContainer.addChild(graphics);
            // graphics.beginFill('red', 0.01)
            graphics.eventMode = 'static';
            graphics.setStrokeStyle({
                alpha: 1,
                color: 0xffffff,
                width: 1
            })
            graphics.rect(i * gridSize, j * gridSize, gridSize, gridSize)
            graphics.fill({
                color: 'red',
                alpha: 0.01,
            })
            graphics.stroke()
            // graphics.lineStyle(1, 0xffffff); // 设置线条颜色和宽度
            // graphics.drawRect(i * gridSize, j * gridSize, gridSize, gridSize); // 绘制矩形格子 
            // graphics.endFill();
            graphics.on('pointerdown', async function (this: Graphics) {
                if (current) {
                    // 如果是范围外的 撤回这次移动
                    if (!highLightPoint.has(this)) {
                        clearHighlightPoint()
                        return
                    }
                    const { x, y, width, height } = this.getBounds()
                    const [pointX, pointY] = this.label.split('_').map(Number)
                    current.tint = 0xFFFFFF;
                    // 计算起点和终点之间的路径
                    const path = calculatePathAStar(map, { x: currentPos[0], y: currentPos[1] }, { x: pointX, y: pointY })?.slice(1);
                    console.log(path); // 输出计算出的路径
                    for (let item of path || []) {
                        const direction =
                            item.x > currentPos[0] ? 'right' :
                                item.x < currentPos[0] ? 'left' :
                                    item.y < currentPos[1] ? 'top' :
                                        'bottom'
                        current.textures = spritesheet.animations[`walk_${direction}`]
                        current.scale = direction === 'right' ? { x: -1, y: 1 } : { x: 1, y: 1 }
                        current.play()
                        const bounds = gridContainer.getChildByName(`${item.x}_${item.y}`)?.getBounds()
                        if (!bounds) return
                        await new Promise(r => {
                            const tween = new Tween(current!)
                                .to({
                                    x: bounds.x + bounds.width / 2,
                                    y: bounds.y + bounds.height / 2
                                }
                                    , 300)
                                .easing(Easing.Linear.None)
                                .onComplete(() => {
                                    current?.stop()
                                    r(undefined)
                                })
                                .start()
                            // Setup the animation loop.
                            function animate(time) {
                                if (!tween.update(time)) {
                                    tween.end()
                                    return
                                }
                                requestAnimationFrame(animate)
                            }
                            requestAnimationFrame(animate)
                        })
                        currentPos = [item.x, item.y]
                    }
                    clearHighlightPoint()
                }
                console.log(`Clicked grid (${i}, ${j})`);
            });
        }
    }

    // Create the SpriteSheet from data and image
    const spritesheet = new Spritesheet(
        Texture.from(atlasData.meta.image),
        atlasData
    );
    // Generate all the Textures asynchronously
    await spritesheet.parse();

    const sprite = new AnimatedSprite(spritesheet.animations.walk_bottom)

    // Set the initial position
    sprite.anchor.set(0.5);
    const pos = gridContainer.getChildAt(0).getBounds()
    sprite.x = pos.x + pos.width / 2;
    sprite.y = pos.y + pos.height / 2;
    currentPos = [0, 0]
    sprite.eventMode = 'static';
    sprite.cursor = 'pointer';
    sprite.loop = true
    sprite.animationSpeed = 0.1
    // Pointers normalize touch and mouse (good for mobile and desktop)
    sprite.on('pointerdown', function (this: AnimatedSprite) {
        current = this
        current.tint = 0x808080; // Gray color
        const visited = getPoints({
            x: currentPos[0],
            y: currentPos[1]
        })
        gridContainer.children.forEach(item => {
            let gamePos = item.label.split('_').map(Number)
            if (isEqual(gamePos, currentPos)) return
            if (visited[gamePos[0]][gamePos[1]]) {
                if (item instanceof Graphics) {
                    const bounds = item.getLocalBounds()
                    item.clear()
                    item.rect(bounds.x + 0.5, bounds.y + 0.5, bounds.width - 1, bounds.height - 1)
                    item.fill({
                        color: 'blue',
                        'alpha': 1,
                    })
                    item.stroke()
                    highLightPoint.add(item)
                }
                item.cursor = 'pointer'
            }
        })
    });

    // Alternatively, use the mouse & touch events:
    // sprite.on('click', onClick); // mouse-only
    // sprite.on('tap', onClick); // touch-only
    app.stage.addChild(sprite);


})
// app.renderer = render;
// The application will create a canvas element for you that you
// can then insert into the DOM



// Create object to store sprite sheet data
const atlasData = {
    frames: {
        walk_bottom_0: {
            frame: { x: 0, y: 0, w: 48, h: 48 },
        },
        walk_bottom_1: {
            frame: { x: 0, y: 48, w: 48, h: 48 },
        },
        walk_top_0: {
            frame: { x: 0, y: 48 * 2, w: 48, h: 48 },
        },
        walk_top_1: {
            frame: { x: 0, y: 48 * 3, w: 48, h: 48 },
        },
        walk_left_0: {
            frame: { x: 0, y: 48 * 4, w: 48, h: 48 },
        },
        walk_left_1: {
            frame: { x: 0, y: 48 * 5, w: 48, h: 48 },
        },
    },
    meta: {
        image: '/assets/Unit_mov1.png',
        format: 'RGBA8888',
        scale: 1
    },
    animations: {
        walk_top: ['walk_top_0', 'walk_top_1'],
        walk_left: ['walk_left_0', 'walk_left_1'],
        walk_bottom: ['walk_bottom_0', 'walk_bottom_1'],
        walk_right: ['walk_left_0', 'walk_left_1'],
    }
}


function clearHighlightPoint() {
    if (!current) return
    current.tint = 0xFFFFFF;
    current = null
    highLightPoint.forEach(item => {
        const bounds = item.getLocalBounds()
        item.clear()
        item.cursor = 'default'
        item.rect(bounds.x + 0.5, bounds.y + 0.5, bounds.width - 1, bounds.height - 1)
        item.fill({
            color: 'red',
            'alpha': 0.01,
        })
        item.stroke()
    })
    highLightPoint.clear()
}


let currentPos: number[] = []


interface Point {
    x: number;
    y: number;
}

const map: number[][] = Array(10).fill(undefined).map(_ => Array(10).fill(1));
map[2][2] = 0
function getPoints(playerPosition: Point) {
    const visited: boolean[][] = [];
    for (let i = 0; i < map.length; i++) {
        visited[i] = new Array(map[0].length).fill(false);
    }
    
    const queue: Point[] = [];
    queue.push(playerPosition);
    visited[playerPosition.x][playerPosition.y] = true;

    const directions: Point[] = [{ x: 1, y: 0 }, { x: -1, y: 0 }, { x: 0, y: 1 }, { x: 0, y: -1 }];

    while (queue.length > 0) {
        const current = queue.shift();
        if (!current) break
        for (const dir of directions) {
            const nextX = current.x + dir.x;
            const nextY = current.y + dir.y;
            if (nextX >= 0 && nextX < map.length && nextY >= 0 && nextY < map[0].length && !visited[nextX][nextY]) {
                const distance = Math.abs(nextX - playerPosition.x) + Math.abs(nextY - playerPosition.y);
                if (distance <= gameStore.maxMoveRange) {
                    visited[nextX][nextY] = true;
                    if (!map[nextX][nextY]) {
                        visited[nextX][nextY] = false;
                    }
                    queue.push({ x: nextX, y: nextY });
                }
            }
        }
    }

    // 输出高亮的移动范围
    for (let i = 0; i < map.length; i++) {
        for (let j = 0; j < map[0].length; j++) {
            if (visited[i][j]) {
                console.log(`(${i}, ${j}) 可移动`);
                // 在游戏中展示高亮的移动范围
                // 可以在实际项目中将这些可移动的坐标用于高亮显示格子等操作
            }
        }
    }

    return visited
}

function calculatePathAStar(map: number[][], start: Point, end: Point): Point[] | null {
    const open: Point[] = [start];
    const cameFrom: Map<string, Point> = new Map();
    const gScore: Map<string, number> = new Map();
    gScore.set(`${start.x},${start.y}`, 0);

    while (open.length > 0) {
        open.sort((a, b) => (gScore.get(`${a.x},${a.y}`) || Infinity) - (gScore.get(`${b.x},${b.y}`) || Infinity));
        const current = open.shift()!;

        if (current.x === end.x && current.y === end.y) {
            const path: Point[] = [end];
            let node = end;
            while (cameFrom.has(`${node.x},${node.y}`)) {
                node = cameFrom.get(`${node.x},${node.y}`)!;
                path.unshift(node);
            }
            return path;
        }

        const neighbors = [
            { x: current.x, y: current.y - 1 },
            { x: current.x, y: current.y + 1 },
            { x: current.x - 1, y: current.y },
            { x: current.x + 1, y: current.y }
        ];

        for (const next of neighbors) {
            const nextKey = `${next.x},${next.y}`;
            if (
                next.x >= 0 &&
                next.x < map.length &&
                next.y >= 0 &&
                next.y < map[0].length &&
                map[next.x][next.y] === 1
            ) {

                const tentativeGScore = (gScore.get(`${current.x},${current.y}`) ?? Infinity) + 1;
                if (tentativeGScore < (gScore.get(nextKey) ?? Infinity)) {
                    cameFrom.set(nextKey, current);
                    gScore.set(nextKey, tentativeGScore);
                    if (!open.some(p => p.x === next.x && p.y === next.y)) {
                        open.push(next);
                    }
                }
            }
        }
    }

    return null;
}

const highLightPoint = new Set<Graphics>()

let current: AnimatedSprite | null = null

